package fr.mywiki.model.ejbAdapter;

import java.io.Serializable;
import java.rmi.RemoteException;
import java.util.Collection;
import java.util.Iterator;

import javax.ejb.FinderException;
import javax.ejb.ObjectNotFoundException;

import fr.mywiki.model.ValueInterface;



/**
 * <p>
 * The basic superclass to manipulate all persistent objects (one should prevent from using beans as
 * much as possible). By using this superclass, changes can be done on an object without being
 * directly done on the database. Changes will be committed by using the method <code>update</code>.
 * </p>
 * <p>
 * The idea of such a class is to be able to have easy access to every field of every data field.
 * Therefore, an object extending the <code>Value</code> class will be linked to an ejb and have
 * accessors to every field of the corresponding bean.
 * </p>
 * <p>
 * Every Value Object is serializable, that is to say it must implement <code>writeObject</code>
 * and <code>readObject</code> methods. Therefore, its attributes/fields must themselves be
 * serializable.
 * </p>
 * 
 * @author tlombard
 */
public abstract class Value implements Serializable, ValueInterface {
	private static final long serialVersionUID = 2L;
	
	public static final String FIELD_ID = "id";
	
	/** The type of the object (which table does it correspond ?) */
	public static final String TYPE_ENT = "";
	
	/** The list of fields for this type */
	public static final String[] FIELDS = {};
	
	/** Identifier of the value (there is always that field) */
	private Long id;

	public Value() {}
	
	/**
	 * Updates the value of this object into the database. Validates/commits all the modifications
	 * done to the offline object.
	 */
	public void update() throws ObjectNotFoundException, RemoteException {
		ServicesFacade.getInstance().update(this);
	}

	/**
	 * Returns the values linked to this object by the relation relName.
	 * 
	 * @param relName the name of the relation to consider.
	 * @return a <code>Collection</code> of <code>Value</code> objects.
	 */
	public Collection getLinks(String relName) throws RemoteException, FinderException {
		return ServicesFacade.getInstance().getLinks(this,relName);
	}

	/**
	 * Adds a link between this object and the one given in parameter <tt>added</tt>. The
	 * considered link is <tt>relName</tt>.
	 * 
	 * @param relName the name of the relation to consider.
	 * @param added a <code>Value</code> object of the correct type
	 */
	public void addLink(String relName, Value added) throws RemoteException, FinderException {
		ServicesFacade.getInstance().addLink(this, added, relName);
	}

	/**
	 * Adds links between this object and the ones contained in the collection given in parameter
	 * <tt>added</tt>. The considered link if <tt>relName</tt>.
	 * 
	 * @param relName the name of the relation to consider.
	 * @param added a <code>Collection</code> of <code>Value</code> objects of the correct type.
	 */
	public void addLinks(String relName, Collection added) throws RemoteException, FinderException {
		Iterator itAdded = added.iterator();
		while (itAdded.hasNext())
			addLink(relName, (Value) itAdded.next());
	}

	/**
	 * Indicates if the present object has a relation with the <code>value</code> object
	 * <tt>linked</tt>, the considered relation being <tt>relName</tt>.
	 * 
	 * @param relName the name of the relation to consider.
	 * @param linked a <code>Value</code> object.
	 */
	public boolean isLinked(String relName, Value linked) throws RemoteException, FinderException {
		return ServicesFacade.getInstance().getLinks(this, relName).contains(linked);
	}

	/**
	 * Removes the link between this object and the <code>value</code> object <tt>removed</tt>,
	 * the considered relation being <tt>relName</tt>.
	 * 
	 * @param relName the name of the relation to consider.
	 * @param removed a <code>Value</code> object.
	 */
	public void removeLink(String relName, Value removed) throws RemoteException, FinderException {
		ServicesFacade.getInstance().removeLink(this, removed, relName);
	}

	/**
	 * Removes all the links to this object via the considered relation <tt>relName</tt>.
	 * 
	 * @param relName the name of the relation to consider.
	 */
	public void removeAllLinks(String relName) throws RemoteException, FinderException {
		Iterator itRemoved = ServicesFacade.getInstance().getLinks(this, relName).iterator();
		while (itRemoved.hasNext())
			ServicesFacade.getInstance().removeLink(this, (Value) itRemoved.next(), relName);
	}
	
	/**
	 * Definitely removes this object from the database.
	 */
	public void remove() throws ObjectNotFoundException, RemoteException {
		DataController.removeValue(this);
	}

	/** Returns the identifier of the <code>Value</code> object. */
	public Long getId() {
		return id;
	}
	
	/**
	 * Returns the list of fields composing this <code>Value</code> type.
	 * 
	 * @return an array of <code>String</code> objects.
	 */
	public String[] getFields() {
		return FIELDS;
	}
	
	/**
	 * Two <code>Value</code> objects are equal if they represent the same
	 * object.
	 */
	public boolean equals(Object obj) {
		if (obj != null && obj instanceof Value) {
			Value val = (Value) obj;
			return (id.equals(val.getId()) && getTypeEnt().equals(val.getTypeEnt()));
		}
		return false;
	}

	/** Sets the value of the identifier of this value */
	public void setId(Long id) {
		this.id = id;
	}
	
	/** Displays information on this value */
	public String toString() {
		return getTypeEnt() + "[" + getId() + "]";
	}
}
